package cn.changein.framework.config.web;

import cn.changein.framework.config.Interceptor.JwtTokenInterceptor;
import cn.changein.framework.config.filter.ApiSignatureFilter;
import cn.changein.framework.config.filter.CommonFilter;
import cn.changein.framework.config.filter.ThreadContextHolderFilter;
import cn.changein.framework.core.listener.ConfigListener;
import cn.changein.framework.xss.XssFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.unit.DataSize;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.MultipartConfigElement;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * web 配置类
 *

 * @date: 2020-02-20
 * @copyright: 广州澄境科技有限公司
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    //获取配置的上传文件的系统临时文件夹路径
    @Value("${file.tempfilePath}")
    private String tempfilePath;

    //获取配置的上传文件的系统临时文件夹路径
    @Value("${file.uploadPath}")
    private String uploadPath;

    @Value("${system.host:}")
    private String host;

    @Value("${system.api.secret}")
    private String apiSecret;

    /**
     * 配置string解析器放在json解析器前边
     *
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        HttpMessageConverter<?> httpMessageConverter = converters.get(0);
        converters.remove(0);
        converters.add(2, httpMessageConverter);
    }

    /**
     * 静态资源映射
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String property = System.getProperty("user.dir");
        //swagger
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

        //本应用
        registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");

        //流程设计器
        registry.addResourceHandler("/activiti-editor/**").addResourceLocations("classpath:/activiti-editor/");
        //图片访问
        registry.addResourceHandler("/file/**").addResourceLocations("file:" + property + File.separator + uploadPath);
    }

    /**
     * 默认错误页面，返回json
     *
     * @Bean("error") public CustomErrorView error() {
     * return new CustomErrorView();
     * }
     * <p>
     * /**
     * druidServlet注册
     */
    @Bean
    public ServletRegistrationBean druidServletRegistration() {
        ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet());
        registration.addUrlMappings("/druid/*");
        return registration;
    }

    /**
     * druid监控 配置URI拦截策略
     */
    @Bean
    public FilterRegistrationBean druidStatFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        //添加过滤规则.
        filterRegistrationBean.addUrlPatterns("/*");
        //添加不需要忽略的格式信息.
        filterRegistrationBean.addInitParameter(
                "exclusions", "/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid,/druid/*");
        //用于session监控页面的用户名显示 需要登录后主动将username注入到session里
        filterRegistrationBean.addInitParameter("principalSessionName", "username");
        return filterRegistrationBean;
    }

    /**
     * druid数据库连接池监控
     */
    @Bean
    public DruidStatInterceptor druidStatInterceptor() {
        return new DruidStatInterceptor();
    }

    @Bean
    public JdkRegexpMethodPointcut druidStatPointcut() {
        JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();
        String patterns = "cn.changein.framework.modular.*.service.*";
        //可以set多个
        druidStatPointcut.setPatterns(patterns);
        return druidStatPointcut;
    }

    /**
     * druid数据库连接池监控
     */
    @Bean
    public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator() {
        BeanTypeAutoProxyCreator beanTypeAutoProxyCreator = new BeanTypeAutoProxyCreator();
        beanTypeAutoProxyCreator.setTargetBeanType(DruidDataSource.class);
        beanTypeAutoProxyCreator.setInterceptorNames("druidStatInterceptor");
        return beanTypeAutoProxyCreator;
    }

    /**
     * druid 为druidStatPointcut添加拦截
     *
     * @return
     */
    @Bean
    public Advisor druidStatAdvisor() {
        return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());
    }

    /**
     * xssFilter注册
     */
    @Primary
    @Bean
    public FilterRegistrationBean xssFilterRegistration() {
        XssFilter xssFilter = new XssFilter();
        xssFilter.setUrlExclusion(Arrays.asList("/notice/add", "/notice/update", "/excelExportDeploy/editItem", "/excelExportDeploy/addItem"));
        FilterRegistrationBean registration = new FilterRegistrationBean(xssFilter);
        registration.addUrlPatterns("/*");
        return registration;
    }

    @Bean
    @Primary
    public FilterRegistrationBean<CommonFilter> commonFilter() {
        CommonFilter commonFilter = new CommonFilter(host);
        FilterRegistrationBean<CommonFilter> registration = new FilterRegistrationBean<>(commonFilter);
        registration.addUrlPatterns("/*");
        return registration;
    }

    //api 前面验证
    @Bean
    @Order(2)
    public FilterRegistrationBean<ApiSignatureFilter> apiSignatureFilter() {
        ApiSignatureFilter apiSignatureFilter = new ApiSignatureFilter(apiSecret);
        FilterRegistrationBean<ApiSignatureFilter> registration = new FilterRegistrationBean<>(apiSignatureFilter);
        registration.addUrlPatterns("/api/*");
        return registration;
    }

    @Bean
    @Order(3)
    public FilterRegistrationBean<ThreadContextHolderFilter> threadContextHolderFilter() {
        ThreadContextHolderFilter threadContextHolderFilter = new ThreadContextHolderFilter();
        FilterRegistrationBean<ThreadContextHolderFilter> registration = new FilterRegistrationBean<>(threadContextHolderFilter);
        registration.addUrlPatterns("/api/*");
        return registration;
    }


    /**
     * RequestContextListener注册
     */
    @Bean
    public ServletListenerRegistrationBean<RequestContextListener> requestContextListenerRegistration() {
        return new ServletListenerRegistrationBean<>(new RequestContextListener());
    }

    /**
     * ConfigListener注册
     */
    @Bean
    public ServletListenerRegistrationBean<ConfigListener> configListenerRegistration() {
        return new ServletListenerRegistrationBean<>(new ConfigListener());
    }

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        String sysDirPath = System.getProperty("user.dir");
        MultipartConfigFactory factory = new MultipartConfigFactory();
        //允许上传的文件最大值
        factory.setMaxFileSize(DataSize.parse("100MB"));
        /// 设置总上传数据总大小
        factory.setMaxRequestSize(DataSize.parse("1024MB"));
        String sysTempFilePath = tempfilePath.startsWith("/") ? tempfilePath : "/" + tempfilePath;
        //设置临时文件路径，以防长时间不操作后删除临时文件导致报错
        File f = new File(sysTempFilePath);
        if (!f.exists())
            f.mkdirs();

        factory.setLocation(sysTempFilePath);
        return factory.createMultipartConfig();

    }

    /**
     * 验证码生成相关
     */
    @Bean
    public DefaultKaptcha kaptcha() {
        Properties properties = new Properties();
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.border.color", "105,179,90");
        properties.put("kaptcha.textproducer.font.color", "blue");
        properties.put("kaptcha.image.width", "125");
        properties.put("kaptcha.image.height", "45");
        properties.put("kaptcha.textproducer.font.size", "45");
        properties.put("kaptcha.session.key", "code");
        properties.put("kaptcha.textproducer.char.length", "4");
        properties.put("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }

    /**
     * @Description: 添加拦截器
     * @Date:2021/1/23 17:44
     * @Param: [registry]

     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtTokenInterceptor()).addPathPatterns("/api/**");
    }

}

